package mrusanov.battle

import mrusanov.team.Team
import util.Random
import mrusanov.buildings.Arena
import mrusanov.tournament.MatchInfo

object Battle {
	val PLAYERS_COUNT = 6
	val POINTS_TO_WIN = 6
}

class Battle(val hostTeam: Team, val guestTeam: Team, val arena: Arena) {

	var random = new Random
	val miniArenas = arena.miniArenasTypes map (new MiniArena(_, this))
	private var _playerStates: Map[Team, Vector[PlayerState]] = Map()
	private var _swapped: Map[Team, Boolean] = Map()

	resetSwaps()

	def this(hostTeam: Team, guestTeam: Team) {
		this(hostTeam, guestTeam, hostTeam.club.buildings.arena)
	}

	private def resetSwaps() {
		_swapped += (hostTeam -> false)
		_swapped += (guestTeam -> false)
	}

	def swapped = _swapped
	def playerStates(team: Team) = _playerStates(team)

	def tookPartInBattle(team: Team) = hostTeam == team || guestTeam == team

	def playRound(): List[AttackInfo] = {
		require(!isOver, "Battle is already isOver")
		require(canBeTurnOver(hostTeam), "Host team is unable to start new round")
		require(canBeTurnOver(guestTeam), "Guest team is unable to start new round")

		resetSwaps()

		miniArenas.filterNot(_.isOver).map(_.playRound()).flatten
	}

	def isTurnOver(team: Team) = swapped(team) && !needToMoveVictoriousPlayer(team)

	def canBeTurnOver(team: Team) = !needToMoveVictoriousPlayer(team)

	private def needToMoveVictoriousPlayer(team: Team): Boolean = {
		miniArenas exists (canVictoriousPlayerBeMovedFromArena(team, _))
	}

	def canVictoriousPlayerBeMovedFromArena(team: Team, arena: MiniArena): Boolean = {
		if (!arena.isOver || arena.getPlayer(team).isEmpty) {
			return false
		}

		miniArenas.exists(ma => !ma.isOver && ma.getPlayer(team).isEmpty)
	}

	def hostPoints = points(hostTeam)
	def guestPoints = points(guestTeam)

	private def points(team: Team): Int = {
		(miniArenas filter (_.winningTeam == Some(team))).size
	}

	def initAndPutPlayers() {
		for (team <- List(hostTeam, guestTeam)) {
			val chosenPlayers = team.playersForMatch
			val shuffledPlayers = random.shuffle(chosenPlayers)
			val states = shuffledPlayers map (PlayerState(_))
			_playerStates += (team -> states)
			for ((player, mini) <- states zip miniArenas) {
				mini.addPlayer(player)
			}
		}
	}

	def isOver = hostPoints >= Battle.POINTS_TO_WIN || guestPoints >= Battle.POINTS_TO_WIN

	def swapPlayers(first: PlayerState, second: PlayerState) {
		if (first == second) {
			return
		}

		require(first.team == second.team, "Swapped players must be from same team")

		val team = first.team

		require(!swapped(team), "This team already did its swap!")

		var firstPlayerArena: Option[MiniArena] = None
		var secondPlayerArena: Option[MiniArena] = None

		for (arena <- miniArenas) {
			if (arena.getPlayer(team) == Some(first)) {
				firstPlayerArena = Some(arena)
			}

			if (arena.getPlayer(team) == Some(second)) {
				secondPlayerArena = Some(arena)
			}
		}

		assume(firstPlayerArena.isDefined && secondPlayerArena.isDefined)

		firstPlayerArena.get.removePlayer(first)
		secondPlayerArena.get.removePlayer(second)

		firstPlayerArena.get.addPlayer(second)
		secondPlayerArena.get.addPlayer(first)

		_swapped += (team -> true)
	}

	def moveVictoriousPlayerToNewArena(player: PlayerState, arena: MiniArena) {
		require(!arena.isOver, "Arena duel is finished")
		require(arena.getPlayer(player.team).isEmpty, "No place for this player on this arena")
		require(player.alive, "Player must be alive")

		val prevArena = findMiniArenaByPlayer(player)
		prevArena match {
			case None => throw new IllegalArgumentException("Player is not found!")
			case Some(ar) =>
				require(ar.isOver, "Duel must be finished!")
				ar.removePlayer(player)
		}

		arena.addPlayer(player)
	}

	private def findMiniArenaByPlayer(player: PlayerState): Option[MiniArena] = {
		miniArenas.find({ ar =>
			ar.duelists.values.exists(_ == Some(player))
		})
	}

}
